<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */

namespace App\Logic;

use App\Model\ApplyAnchor;
use App\Model\FollowAnchor;
use App\Model\Live;
use App\Model\LiveBlacklist;
use App\Model\LiveGift;
use App\Model\LiveManager;
use App\Model\LiveSession;
use App\Model\LiveSessionGift;
use App\Model\Play;
use App\Model\User;
use App\Model\UserModelAnchor;
use App\Service\LiveService;
use App\Service\SettingService;
use App\Utils\Enum\AccountEnum;
use App\Utils\Enum\LiveEnum;
use App\Utils\Enum\MatchEnum;
use App\Websocket\ImWebsocket;
use Exception;
use Hyperf\Context\ApplicationContext;
use Hyperf\DbConnection\Db;
use Hyperf\Redis\Redis;
use Hyperf\Tappable\HigherOrderTapProxy;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use function Hyperf\Support\env;

class LiveLogic
{
    /**
     * 获取房间在线
     * @param $roomId
     * @return int
     */
    public static function getRoomOnlineCount($roomId): int
    {
        $online = 0;
        try {
            $redis = ApplicationContext::getContainer()->get(Redis::class);
            $online = (int)$redis->sCard(ImWebsocket::KeyGroup((string)$roomId));
        } catch (NotFoundExceptionInterface|ContainerExceptionInterface|\RedisException $e) {
        }
        return $online;
    }

    /**
     * 概览
     * @param $userid
     * @return int[]
     * @throws Exception
     */
    public static function overview($userid): array
    {
        $anchorInfo = UserModelAnchor::query()->where('userid', $userid)->with(['assistant'])->first();
        if (!$anchorInfo) {
            throw new Exception('当前角色不可操作');
        }
        $overview = [
            'accountStatus' => 0,
            'liveStatus' => $anchorInfo['live_status'],
            'online' => self::getRoomOnlineCount($anchorInfo['room_id']),
            'fansCount' => 0,
            'todayFansCount' => '-',
            'monthFansCount' => '-',
            'banTime' => '',
            'todayGiftIncome' => LiveSessionGift::query()->where(['room_id' => $anchorInfo['room_id'], 'idx_date' => date('Ymd')])->sum('amount'),
            'assistant' => [
                'userId' => $anchorInfo['assistant']['id'],
                'userNick' => $anchorInfo['assistant']['nickname'],
                'userAvatar' => img_url($anchorInfo['assistant']['avatar'])
            ]
        ];
        if (!$anchorInfo['room_id']) {
            return $overview;
        }
        $liveInfo = Live::query()->where('userid', $userid)->first();
        $overview['accountStatus'] = $liveInfo['ban_time'] == 0 ? 1 : 2;
        $overview['fansCount'] = $anchorInfo['fans_count'];
        $overview['banTime'] = $liveInfo['ban_time'];
        $overview['banEndTime'] = $liveInfo['ban_endtime'];
        return $overview;
    }

    /**
     * 获取房间配置
     * @param $userId
     * @return array
     */
    public static function getRoomInfo($userId): array
    {
        $liveInfo = Live::query()->where('userid', $userId)->with(['match', 'column', 'assistant'])->first();
        if ($liveInfo) {
            $pushStreamAddress = LiveService::createPushStreamAddress($liveInfo['room_id']);
            $info = [
                'roomId' => $liveInfo['room_id'],
                'roomName' => $liveInfo['room_name'],
                'matchInfo' => null,
                'roomCover' => img_url($liveInfo['room_cover']),
                'columnId' => $liveInfo['column_id'],
                'columnName' => $liveInfo['column']['title'] ?? '',
                'introduce' => $liveInfo['introduce'],
                'announcement' => $liveInfo['announcement'],
                'assistant' => [
                    'userId' => $liveInfo['assistant']['id'],
                    'userNick' => $liveInfo['assistant']['nickname'],
                    'userAvatar' => img_url($liveInfo['assistant']['avatar']),
                ],
                'pushStreamAddress' => $pushStreamAddress,
                'obs' => self::convertOBSAddress($pushStreamAddress),
            ];
            if ($liveInfo['match']) {
                $info['matchInfo'] = [
                    'sportId' => $liveInfo['match']['sport_id'],
                    'matchId' => $liveInfo['match']['match_id'],
                    'gameId' => $liveInfo['match']['game_id'],
                    'gameName' => $liveInfo['match']['game_name'],
                    'gameLogo' => img_url($liveInfo['match']['game_logo'], 80),
                    'homeTeamName' => $liveInfo['match']['home_team_name'],
                    'homeTeamLogo' => img_url($liveInfo['match']['home_team_logo'], 80),
                    'awayTeamName' => $liveInfo['match']['away_team_name'],
                    'awayTeamLogo' => img_url($liveInfo['match']['home_team_logo'], 80),
                    'matchStatus' => $liveInfo['match']['match_status'],
                    'matchTime' => $liveInfo['match']['match_time'],
                ];
            }
        } else {
            $applyInfo = ApplyAnchor::query()->where(['userid' => $userId, 'audit_status' => 1])->orderBy('id', 'desc')->first();
            $anchorInfo = UserModelAnchor::query()->where('userid', $userId)->with(['assistant'])->first();
            $info = [
                'roomId' => '',
                'roomName' => '',
                'matchInfo' => null,
                'roomCover' => '',
                'columnId' => $applyInfo['live_column_id'] ?? 0,
                'columnName' => $applyInfo['live_column_name'] ?? '',
                'introduce' => '',
                'announcement' => '',
                'assistant' => [
                    'userId' => $anchorInfo['assistant']['id'],
                    'userNick' => $anchorInfo['assistant']['nickname'],
                    'userAvatar' => img_url($anchorInfo['assistant']['avatar']),
                ],
                'pushStreamAddress' => '',
                'obs' => [
                    'server' => '',
                    'code' => ''
                ],
            ];
        }
        return $info;
    }

    /**
     * 设置房间信息
     * @param $userId
     * @param $input
     * @return true
     * @throws Exception
     */
    public static function setRoomInfo($userId, $input): true
    {
        $anchorInfo = UserModelAnchor::query()->where('userid', $userId)->first();
        if (!$anchorInfo) {
            throw new Exception('当前角色不可操作');
        }
        if (str_starts_with($input['roomCover'], env('COS_URL'))) {
            $input['roomCover'] = substr($input['roomCover'], strlen(env('COS_URL')));
        }
        if (empty($input['matchId'])) {
            throw new Exception('请选择比赛');
        }
        $matchInfo = Play::query()->where('match_id', $input['matchId'])->first();
        if (!$matchInfo) {
            throw new Exception('比赛不存在');
        }
        $liveInfo = Live::query()->where('userid', $userId)->first();
        if ($liveInfo) {
            Live::query()->where('id', $liveInfo['id'])->update([
                'room_name' => $input['roomName'],
                'room_cover' => $input['roomCover'],
                'announcement' => $input['announcement'],
                'introduce' => $input['introduce'],
                'match_id' => $matchInfo['match_id'],
                'match_time' => $matchInfo['match_time'],
                'match_status' => $matchInfo['match_status'],
            ]);
        } else {
            $anchorInfo = UserModelAnchor::query()->where(['userid' => $userId])->first();
            $roomId = self::createRoomId();
            $live = Live::create([
                'userid' => $userId,
                'room_id' => $roomId,
                'room_name' => $input['roomName'],
                'column_id' => $anchorInfo['column_id'],
                'assistant_userid' => $anchorInfo['assistant_userid'],
                'announcement' => $input['announcement'],
                'introduce' => $input['introduce'],
                'match_id' => $matchInfo['match_id'],
                'match_time' => $matchInfo['match_time'],
                'match_status' => $matchInfo['match_status'],
                'room_cover' => $input['roomCover'],
            ]);
            if (!$live) {
                throw new Exception('创建失败');
            }
            UserModelAnchor::query()->where('userid', $userId)->update([
                'room_id' => $roomId
            ]);
        }
        return true;
    }

    /**
     * 获取正在直播的主播
     * @param $input
     * @return array
     */
    public static function getLiveAnchorList($input): array
    {
        [$pageNum, $pageSize, $offset] = parsePageParams($input);
        $where = ['status' => LiveEnum::STATUS_LIVING];
        $query = Live::query()->where($where);
        $total = $query->count();
        if ($total) {
            $rs = $query->with(['user'])->offset($offset)->limit($pageSize)->orderBy('listorder')->orderBy('visit_history', 'desc')->get();
            $data = [];
            foreach ($rs as $r) {
                $data[] = [
                    'roomId' => $r['room_id'],
                    'roomName' => $r['room_name'],
                    'roomImage' => img_url($r['room_cover']),
                    'userId' => $r['user']['id'],
                    'userName' => $r['user']['username'],
                    'userNickName' => $r['user']['nickname'],
                    'userAvatar' => img_url($r['user']['avatar'], 90),
                    'liveStatus' => $r['status'],
                    'playStreamAddress' => $r['play_stream_address'],
                    'playStreamAddress2' => $r['play_stream_address2'],
                    'visitHistory' => $r['visit_history'],
                    'attentionStatus' => 0,
                ];
            }
        }

        return [
            'total' => $total,
            'pages' => ceil($total / $pageSize),
            'records' => $data ?? [],
        ];
    }

    /**
     * 获取主播列表.
     * @param mixed $userid
     * @param mixed $input
     */
    public static function getAnchorList($userid, $input): array
    {
        $pageNum = max(1, intval($input['pageNum'] ?? 1));
        $pageSize = intval($input['pageSize'] ?? 20);
        $where = [['status', '<>', LiveEnum::STATUS_FORBIDDEN]];
        if (!empty($input['query']['columnId'])) {
            $where[] = ['column_id', '=', (int)$input['query']['columnId']];
        }
        $query = Live::query()->where($where);
        $total = $query->count();
        if ($total) {
            $rs = $query->with(['user'])->offset(($pageNum - 1) * $pageSize)->limit($pageSize)->orderBy('status', 'desc')->orderBy('listorder')->get();
            $data = [];
            $anchorUserid = [];
            foreach ($rs as $r) {
                $data[] = [
                    'roomId' => $r['room_id'],
                    'roomName' => $r['room_name'],
                    'roomImage' => img_url($r['room_cover']),
                    'userId' => $r['user']['id'],
                    'userName' => $r['user']['username'],
                    'userNickName' => $r['user']['nickname'],
                    'userAvatar' => img_url($r['user']['avatar'], 90),
                    'liveStatus' => $r['status'],
                    'playStreamAddress' => $r['play_stream_address'],
                    'playStreamAddress2' => $r['play_stream_address2'],
                    'visitHistory' => $r['visit_history'],
                    'attentionStatus' => 0,
                ];
                $anchorUserid[] = $r['userid'];
            }
            if ($userid && !empty($anchorUserid)) {
                $follows = FollowAnchor::query()->where([['userid', '=', $userid], ['anchor_userid', 'in', $anchorUserid]])->get();
                foreach ($follows as $f) {
                    $idx = array_search($f['anchor_userid'], $anchorUserid);
                    $data[$idx]['attentionStatus'] = 1;
                }
            }
        }
        return [
            'total' => $total,
            'pages' => ceil($total / $pageSize),
            'records' => $data ?? [],
        ];
    }

    /**
     * 获取主播排行榜.
     * @param mixed $userid
     * @param mixed $topNum
     */
    public static function getAnchorRankList($userid, $topNum = 200): array
    {
        $rs = UserModelAnchor::whereHas('live')->with(['live', 'user'])->orderBy('fans_count', 'desc')->limit($topNum)->get();
        $data = [];
        $anchorUserIds = [];
        foreach ($rs as $r) {
            $data[] = [
                'userId' => $r['user']['id'],
                'userNick' => $r['user']['nickname'],
                'userAvatar' => img_url($r['user']['avatar'], 90),
                'roomId' => $r['live']['room_id'],
                'liveStatus' => $r['live']['status'],
                'followed' => 0,
            ];
            $anchorUserIds[] = $r['userid'];
        }
        if (!empty($anchorUserIds)) {
            $followList = FollowAnchor::query()->where('userid', $userid)->whereIn('anchor_userid', $anchorUserIds)->get();
            if (!empty($followList)) {
                foreach ($followList as $r) {
                    $idx = array_search($r['anchor_userid'], $anchorUserIds);
                    $data[$idx]['followed'] = 1;
                }
            }
        }
        return $data;
    }

    /**
     * 获取直播记录.
     * @param mixed $userid
     * @param mixed $input
     */
    public static function getRecord($userid, $input): array
    {
        $pageNum = max(1, intval($input['pageNum'] ?? 1));
        $pageSize = intval($input['pageSize'] ?? 20);
        $total = LiveSession::query()->where('userid', $userid)->count();
        if ($total) {
            $records = LiveSession::query()->where('userid', $userid)->offset(($pageNum - 1) * $pageSize)->limit($pageSize)->orderBy('id', 'desc')->get()->toArray();
            array_walk($records, function (&$v) {
                $v['directionName'] = AccountEnum::getDirection($v['direction']);
                $v['typename'] = AccountEnum::getTypeName($v['typeid']);
                $v['startTime'] = date('Y-m-d H:i:s', $v['start_time']);
                unset($v['start_time']);
            });
        }
        return [
            'total' => $total,
            'pages' => ceil($total / $pageSize),
            'records' => $records ?? [],
        ];
    }

    /**
     * 开始直播
     * @param $pushStreamData
     * @return false|int
     */
    public static function startLive($pushStreamData): false|int
    {
        if ($pushStreamData['errcode'] != 0) {
            return false;
        }
        $live = Live::query()->where('room_id', $pushStreamData['stream_id'])->first();
        if (!$live || $live['status'] == 9 || ($live['ban_time'] && time() < $live['ban_endtime'])) {
            return false;
        }
        $update = ['status' => LiveEnum::STATUS_LIVING];
        if (time() - $live['cute_stream_time'] > 60) {
            $session = self::createLiveSession($live);
            $update['session_id'] = $session['id'];
        }
        $update['cute_stream_time'] = 0;
        return Live::query()->where('id', $live['id'])->update($update);
    }

    /**
     * 创建直播场次
     * @param $live
     * @param $startTime
     * @return array
     */
    private static function createLiveSession($live, $startTime = 0): array
    {
        $session = LiveSession::create([
            'userid' => $live['userid'],
            'room_id' => $live['room_id'],
            'live_date' => date('Ymd', $startTime ?? time()),
            'live_time' => 0,
            'start_time' => $startTime ?? time(),
        ]);
        return $session->toArray();
    }

    /**
     * 开播.
     * @param mixed $userid
     * @param mixed $input
     * @throws Exception
     */
    public static function startLiveOld($userid, $input): true
    {
        $live = Live::query()->where('userid', $userid)->first();
        if ($live) {
            if ($live['status'] == LiveEnum::STATUS_LIVING) {
                throw new Exception('已经在直播中了，若需重新开始，请先关播');
            }
            if ($live['status'] == LiveEnum::STATUS_FORBIDDEN) {
                throw new Exception('房间已封禁，无法开播');
            }
            $match = Play::query()->where('match_id', $input['matchId'])->first();
            if ($match['status'] > MatchEnum::MATCH_STATUS_ING) {
                throw new Exception('该赛事已结束');
            }

            if ($live['push_steam_address'] == '') {
                throw new Exception('请先获取推流地址');
            }

            Db::beginTransaction();
            $liveSession = LiveSession::create([
                'userid' => $userid,
                'room_id' => $live['room_id'],
                'live_date' => date('Ymd'),
                'start_time' => time(),
                'update_time' => time(),
            ]);
            $update = [
                'room_name' => $input['roomName'],
                'room_banner' => $input['roomBanner'],
                'match_id' => $match['matchId'],
                'announcement' => $input['announcement'],
                'session_id' => $liveSession['id'],
                'status' => LiveEnum::STATUS_LIVING,
            ];
            $rt1 = Live::query()->where('id', $live['id'])->update($update);
            if ($rt1 && $liveSession) {
                Db::commit();
                LiveService::resumeLiveStream($live['room_id']);
            } else {
                Db::rollBack();
                throw new Exception('开启失败');
            }
        } else {
            throw new Exception('请先获取推流地址');
        }
        return true;
    }

    /**
     * 关注/取关主播.
     * @param mixed $userid
     * @param mixed $anchorUserid
     * @return int
     */
    public static function followAnchor($userid, $anchorUserid): int
    {
        $info = FollowAnchor::query()->where(['userid' => $userid, 'anchor_userid' => $anchorUserid])->first();
        if ($info) {
            $ret = FollowAnchor::query()->where('id', $info['id'])->delete();
            if ($ret) {
                UserModelAnchor::query()->where('userid', $anchorUserid)->decrement('fans_count');
            }
            $followed = 0;
        } else {
            FollowAnchor::create([
                'userid' => $userid,
                'anchor_userid' => $anchorUserid,
                'add_time' => time(),
            ]);
            $followed = 1;
        }
        return $followed;
    }

    /**
     * @param mixed $anchorUserid
     * @param mixed $roomId
     * @throws Exception
     */
    public static function getAnchorDetail($userid = 0, $roomId = 0, $anchorUserid = 0): array
    {
        if (!$roomId && !$anchorUserid) {
            throw new Exception('参数错误');
        }
        if ($roomId) {
            $where = ['room_id' => $roomId];
        } else {
            $where = ['userid' => $anchorUserid];
        }
        $live = Live::with(['user', 'anchor'])->where($where)->first();
        if (!$live) {
            throw new Exception('未找到该主播');
        }
        $followed = 0;
        if ($userid && FollowAnchor::query()->where(['userid' => $userid, 'anchor_userid' => $live['userid']])->exists()) {
            $followed = 1;
        }
        $ads = SettingService::getGroupSetting('ad');
        return [
            'roomId' => $live['room_id'],
            'roomName' => $live['room_name'],
            'chatStatus' => 1,
            'fansCount' => $live['anchor']['fans_count'],
            'roomCover' => $live['room_cover'],
            'announcement' => $live['announcement'],
            'roomIntroduce' => '',
            'liveAddress' => '',
            'userId' => $live['userid'],
            'userName' => $live['user']['username'],
            'nickName' => $live['user']['nickname'],
            'userAvatar' => img_url($live['user']['avatar'], 80),
            'followed' => $followed,
            'visitHistory' => $live['visit_history'],
            'gameId' => $live['game_id'],
            'matchId' => $live['match_id'],
            'playStreamAddress' => LiveService::createPlayAddress($live['room_id']),
            'playStreamAddress2' => empty($live['play_stream_address2']) ? LiveService::createPlayAddress($live['room_id'], 'm3u8') : $live['play_stream_address2'],
            'liveStatus' => $live['status'],
            'assistantUserid' => $live['assistant_userid'],
            'marquee' => [
                'title' => $ads['ad_live_marquee_title'],
                'url' => $ads['ad_live_marquee_link'],
                'content' => $ads['ad_live_marquee_content']
            ],
            'adIcons' => [
                'app' => [
                    'left' => [
                        'icon' => img_url($ads['ad_live_left_img'], 80),
                        'title' => $ads['ad_live_left_title'],
                        'url' => $ads['ad_live_left_link']
                    ],
                    'right' => [
                        'icon' => img_url($ads['ad_live_right_img'], 80),
                        'title' => $ads['ad_live_right_title'],
                        'url' => $ads['ad_live_right_link']
                    ],
                ],
                'pc' => [
                    'left' => [],
                    'right' => []
                ]
            ]
        ];
    }

    /**
     * 关播.
     * @param mixed $userid
     */
    public static function closeLive($userid): true
    {
        $live = Live::query()->where('userid', $userid)->first();
        if ($live['status'] == LiveEnum::STATUS_LIVING) {
            $endTime = time();
            LiveSession::query()->where('id', $live['session_id'])->update([
                'live_time' => Db::raw('CURRENT_TIMESTAMP() - start_time'),
                'end_time' => $endTime,
                'update_time' => $endTime,
            ]);
            Live::query()->where('id', $live['id'])->update([
                'status' => LiveEnum::STATUS_CLOSED,
                'session_id' => 0,
            ]);
            // 断开推流
            LiveService::dropLiveStream($live['room_id']);
        }
        return true;
    }

    /**
     * 获取推流地址
     * @param mixed $userid
     * @param mixed $isVirtual
     * @throws Exception
     */
    public static function getPushStreamAddress($userid, $isVirtual = false): string
    {
        $live = Live::query()->where('userid', $userid)->first();
        if ($live) {
            if ($live['status'] == LiveEnum::STATUS_LIVING) {
                throw new Exception('正在直播中，无法重新获取推流地址');
            }
            if ($live['status'] == LiveEnum::STATUS_FORBIDDEN) {
                throw new Exception('封禁的直播间无法获取推流地址');
            }
            $pushSteamAddress = LiveService::createPushStreamAddress($live['room_id']);
            $update = [
                'push_stream_address' => $pushSteamAddress,
            ];
            if (!Live::query()->where('id', $live['id'])->update($update)) {
                throw new Exception('获取推流地址失败');
            }
        } else {
            $isAnchor = UserModelAnchor::query()->where('userid', $userid)->exists();
            if (!$isAnchor) {
                throw new Exception('当前账号尚未开通直播权限');
            }
            $roomId = self::createRoomId();

            $pushSteamAddress = LiveService::createPushStreamAddress($roomId);
            $live = Live::create([
                'userid' => $userid,
                'room_id' => $roomId,
                'room_name' => '直播间' . $roomId,
                'status' => LiveEnum::STATUS_CLOSED,
                'is_virtual' => $isVirtual ? 1 : 0,
            ]);
            if (!$live) {
                throw new Exception('获取推流地址失败');
            }
        }
        return $pushSteamAddress;
    }

    /**
     * 获取房间ID.
     * @param mixed $userid
     * @return HigherOrderTapProxy|int|mixed
     */
    public static function getRoomId($userid): mixed
    {
        $roomId = Live::query()->where('userid', $userid)->value('room_id');
        return $roomId ?? 0;
    }

    /**
     * 获取房间管理员.
     * @param mixed $roomId
     */
    public static function getRoomManager($roomId): array
    {
        $rs = LiveManager::with(['user' => function ($query) {
            return $query->select('id', 'nickname', 'avatar');
        }])->where('room_id', $roomId)->orderBy('add_time')->get();
        $data = [];
        foreach ($rs as $r) {
            $data[] = [
                'userid' => $r['userid'],
                'nickname' => $r['user']['nickname'],
                'avatar' => img_url($r['user']['avatar']),
                'addTime' => date('Y-m-d H:i:s', $r['add_time']),
            ];
        }
        return $data;
    }

    /**
     * 设置管理员.
     * @param mixed $roomId
     * @param mixed $userid
     * @throws Exception
     */
    public static function setRoomManager($roomId, $userid): true
    {
        if (!LiveManager::query()->where(['room_id' => $roomId, 'userid' => $userid])->exists()) {
            $manager = LiveManager::create([
                'room_id' => $roomId,
                'userid' => $userid,
                'add_time' => time(),
            ]);
            if (!$manager) {
                throw new Exception('设置失败');
            }
        }
        return true;
    }

    /**
     * 是否为房间管理员.
     * @param mixed $roomId
     * @param mixed $userid
     */
    public static function isRoomManager($roomId, $userid): bool
    {
        return LiveManager::query()->where(['room_id' => $roomId, 'userid' => $userid])->exists();
    }

    /**
     * 是否为房间主播.
     * @param mixed $roomId
     * @param mixed $userid
     */
    public static function isRoomOwner($roomId, $userid): bool
    {
        return Live::query()->where(['room_id' => $roomId, 'userid' => $userid])->exists();
    }

    public static function hasPermissionBlackList($userid)
    {
    }

    /**
     * 获取黑名单.
     * @param mixed $roomId
     * @param mixed $input
     */
    public static function getBlackList($roomId, $input): array
    {
        $pageNum = max(1, intval($input['pageNum'] ?? 1));
        $pageSize = intval($input['pageSize'] ?? 20);
        $total = LiveBlacklist::query()->where('room_id', $roomId)->count();
        if ($total) {
            $rs = LiveBlacklist::with('user')->where('room_id', $roomId)->offset(($pageNum - 1) * $pageSize)->limit($pageSize)->orderBy('id', 'desc')->get()->toArray();
            $data = [];
            foreach ($rs as $r) {
                $data[] = [
                    'id' => $r['id'],
                    'userid' => $r['userid'],
                    'nickname' => $r['user']['nickname'],
                    'username' => $r['user']['username'],
                    'avatar' => img_url($r['user']['avatar']),
                ];
            }
            unset($rs);
        }
        return [
            'total' => $total,
            'pages' => ceil($total / $pageSize),
            'records' => $data ?? [],
        ];
    }

    /**
     * 移除黑名单.
     * @param mixed $roomId
     * @param mixed $userid
     * @return bool
     */
    public static function removeBlackList($roomId, $userid)
    {
        $ret = LiveBlacklist::query()->where(['room_id' => $roomId, 'userid' => $userid])->delete();
        return (bool)$ret;
    }

    /**
     * 添加黑名单.
     * @param mixed $roomId
     * @param mixed $userid
     * @param mixed $opInfo
     * @throws Exception
     */
    public static function addBlackList($roomId, $userid, $opInfo)
    {
        if (!LiveBlacklist::query()->where(['room_id' => $roomId, 'userid' => $userid])->exists()) {
            $ret = LiveBlacklist::create([
                'room_id' => $roomId,
                'userid' => $userid,
                'op_userid' => $opInfo['userid'] ?? 0,
                'op_role' => $opInfo['role'] ?? 9,
                'add_time' => time(),
            ]);
            if (!$ret) {
                throw new Exception('操作失败');
            }
        }
        return true;
    }


    /**
     * 获取最后一次入驻记录
     * @param $userid
     * @return array
     */
    public static function getLastSettledResult($userid): array
    {
        $info = ApplyAnchor::query()->where('userid', $userid)->orderBy('id', 'desc')->first();
        if (!$info) {
            return [];
        } else {
            return [
                'applyTime' => date('Y-m-d H:i', $info['apply_time']),
                'auditTime' => $info['audit_time'] ? date('Y-m-d H:i', $info['audit_time']) : 0,
                'auditStatus' => $info['audit_status'],
                'auditMark' => $info['audit_mark']
            ];
        }
    }

    /**
     * 入驻申请
     * @throws Exception
     */
    public static function settled($userid, $input): array
    {
        $lastRecord = self::getLastSettledResult($userid);
        if (!empty($lastRecord)) {
            if ($lastRecord['auditStatus'] == 0) {
                throw new Exception('不可重复提交申请');
            } else if ($lastRecord['auditStatus'] == 1) {
                throw new Exception('已入驻成功，无需再次提交申请');
            }
        }

        try {
            $ret = ApplyAnchor::create([
                'userid' => $userid,
                'contact' => $input['contact'],
                'telephone' => $input['telephone'],
                'introduce' => $input['introduce'],
                'live_column_id' => $input['liveColumnId'] ?? '',
                'live_column_name' => $input['liveColumnName'] ?? '',
                'idcard' => $input['idcard'] ?? '',
                'idcard_img1' => $input['idcardImg1'] ?? '',
                'idcard_img2' => $input['idcardImg2'] ?? '',
                'apply_time' => time(),
            ]);
            if ($ret) {
                return self::getLastSettledResult($userid);
            } else {
                throw new Exception('申请提交失败');
            }
        } catch (Exception $e) {
            throw new Exception('申请提交异常');
        }
    }

    /**
     * 获取礼物列表
     * @return array
     */
    public static function getGiftList(): array
    {
        $res = LiveGift::query()->orderBy('listorder')->orderBy('id')->get();
        $data = [];
        foreach ($res as $r) {
            $data[] = [
                'id' => $r['id'],
                'tag' => $r['tag'],
                'name' => $r['name'],
                'icon' => img_url($r['icon']),
                'animate' => img_url($r['animate']),
                'coins' => $r['coins']
            ];
        }
        return $data;
    }

    /**
     * 赠送礼物
     * @throws Exception
     */
    public static function sendGift($userid, $roomId, $giftId, $quantity = 1): true
    {
        $quantity = max(1, intval($quantity));
        $live = Live::query()->where('room_id', $roomId)->first();
        if (!$live) {
            throw new Exception('直播间不存在');
        }
        $gift = LiveGift::query()->where('id', $giftId)->first();
        if (!$gift) {
            throw new Exception('礼物不存在');
        }
        $amount = $quantity * $gift['coins'];
        $balance = User::query()->where('id', $userid)->value('coins');
        if ($balance < $amount) {
            throw new Exception('账户余额不足');
        }
        UserLogic::decrCoins($userid, $amount, AccountEnum::TYPE_SEND_GIFTS, sprintf('赠送礼物「%s」x%d', $gift['name'], $quantity));
        UserLogic::incrCoins($live['userid'], $amount, AccountEnum::TYPE_RECEIVE_GIFT, sprintf('直播礼物「%s」x%d', $gift['name'], $quantity));
        LiveSessionGift::create([
            'userid' => $userid,
            'room_id' => $roomId,
            'session_id' => $live['session_id'],
            'gift_id' => $giftId,
            'gift_name' => $gift['name'],
            'gift_coins' => $gift['coins'],
            'payment' => AccountEnum::PAYMENT_BALANCE,
            'quantity' => $quantity,
            'amount' => $amount,
            'idx_date' => date('Ymd'),
            'add_time' => time()
        ]);
        return true;
    }

    /**
     * 获取礼物记录
     * @param $roomId
     * @param $input
     * @return array
     */
    public static function getGiftRecords($roomId, $input): array
    {
        [, $pageSize, $offset] = parsePageParams($input);
        $query = LiveSessionGift::query()->where('room_id', $roomId)->when(isset($input['query']['session_id']), function ($q) use ($input) {
            $q->where('session_id', (int)$input['query']['session_id']);
        })->when(isset($input['query']['date']), function ($q) use ($input) {
            $q->where('idx_date', (int)$input['query']['date']);
        });
        $total = $query->count();
        if ($total) {
            $res = $query->with(['user'])->limit($pageSize)->offset($offset)->orderBy('id', 'desc')->get();
            $records = [];
            foreach ($res as $r) {
                $records[] = [
                    'id' => $r['id'],
                    'roomId' => $r['room_id'],
                    'sessionId' => $r['session_id'],
                    'userId' => $r['userid'],
                    'userNick' => $r['user']['nickname'],
                    'userAvatar' => img_url($r['user']['avatar']),
                    'giftId' => $r['gift_id'],
                    'giftName' => $r['gift_name'],
                    'giftCoins' => $r['gift_coins'],
                    'payment' => $r['payment'],
                    'quantity' => $r['quantity'],
                    'amount' => $r['amount'],
                    'addTime' => $r['add_time']
                ];
            }
        }
        return [
            'total' => $total,
            'pages' => ceil($total / $pageSize),
            'records' => $records ?? []
        ];
    }

    /**
     * 创建房间ID.
     */
    public static function createRoomId(): int
    {
        $roomId = mt_rand(10000000, 99999999);
        if (Live::query()->where('room_id', $roomId)->exists()) {
            $roomId = self::createRoomId();
        }
        return $roomId;
    }

    /**
     * 将推流地址转换成OBS地址
     * @param $pushStreamAddress
     * @return array
     */
    private static function convertOBSAddress($pushStreamAddress): array
    {
        $pos = strrpos($pushStreamAddress, '/') + 1;
        return [
            'server' => substr($pushStreamAddress, 0, $pos),
            'code' => substr($pushStreamAddress, $pos)
        ];
    }
}
